#ifndef NE_STL_INCLUDENE_STL_STRING_
#define NE_STL_INCLUDENE_STL_STRING_

#include <stdarg.h>  // NOLINT
#include <cstdlib>
#include "ne_stl_build.h"
#include "ne_stl_iterator.h"
#include "ne_stl_memory.h"
#include "ne_stl_tool.h"
#include "ne_stl_value_def.h"

#if !defined(NE_STL_OS_WIN)
#include <errno.h>
#endif

namespace nstd {
template <element_malloc_fun_t<char> _malloc = memory::safe_malloc_container_element<char>,
    element_delete_fun_t<char> _delete = memory::safe_delete_container_element<char>>
class _string {
public:
    using value_type = char;

private:
    using string_iterator_type = nstd::iterator_type<char>;
    using const_iterator = nstd::const_iterator<char>;
    using iterator = nstd::iterator<char>;
    using reverse_iterator = nstd::reverse_iterator<char>;
    using const_reverse_iterator = nstd::const_reverse_iterator<char>;

public:
    _string()
        : _str(nullptr)
        , _str_len(0)
        , _str_cap(0)
        , _increaseBy(container_increase_step::value)
        , malloc_fun_(_malloc)
        , delete_fun_(_delete) {
        _setCapacity(0);
        _setLength(0);
    }
    _string(const _string& other)
        : _str(nullptr)
        , _str_len(0)
        , _str_cap(0)
        , _increaseBy(container_increase_step::value)
        , malloc_fun_(_malloc)
        , delete_fun_(_delete) {
        _append(other._str, other._str_len);
    }
    _string(const _string& other, std::size_t pos, std::size_t len = container_npos::value)
        : _str(nullptr)
        , _str_len(0)
        , _str_cap(0)
        , _increaseBy(container_increase_step::value)
        , malloc_fun_(_malloc)
        , delete_fun_(_delete) {
        append(other._str, pos, len);
    }
    _string(const char* copy)
        : _str(nullptr)
        , _str_len(0)
        , _str_cap(0)
        , _increaseBy(container_increase_step::value)
        , malloc_fun_(_malloc)
        , delete_fun_(_delete) {
        _append(copy);
    }
    _string(const char* s, std::size_t n)
        : _str(nullptr)
        , _str_len(0)
        , _str_cap(0)
        , _increaseBy(container_increase_step::value)
        , malloc_fun_(_malloc)
        , delete_fun_(_delete) {
        append(s, 0, n);
    }
    _string(std::size_t n, char c)
        : _str(nullptr)
        , _str_len(0)
        , _str_cap(0)
        , _increaseBy(container_increase_step::value)
        , malloc_fun_(_malloc)
        , delete_fun_(_delete) {
        append(n, c);
    }
    _string(const const_iterator first, const const_iterator second)
        : _str(nullptr)
        , _str_len(0)
        , _str_cap(0)
        , _increaseBy(container_increase_step::value)
        , malloc_fun_(_malloc)
        , delete_fun_(_delete) {
        append(first, second);
    }
    _string(const std::string& other)
        : _string(other.c_str(), other.length()) {}
    _string(_string&& other) {
        _str = other._str;
        _str_len = other._str_len;
        _str_cap = other._str_cap;
        _increaseBy = other._increaseBy;
        malloc_fun_ = other.malloc_fun_;
        delete_fun_ = other.delete_fun_;
        other._str = nullptr;
        other._str_len = 0;
        other._str_cap = 0;
        other._increaseBy = container_increase_step::value;
        other.malloc_fun_ = nullptr;  // not set to _malloc because the implementation may be different across modules
        other.delete_fun_ = nullptr;  // same as above
    }

public:
    _string& operator=(const char* other) {
        if (other != nullptr) {
            _setLength(0);
            _append(other, strlen(other));
        }
        return *this;
    }
    _string& operator=(const _string& other) {
        if (this != &other) {
            _setLength(0);
            _append(other._str, other._str_len);
        }
        return *this;
    }
    _string& operator=(const std::string& std_string) {
        clear();
        append(std_string.c_str());
        return *this;
    }
    operator std::string() const {
        std::string ret(c_str());
        return ret;
    }
    //	Destructor
public:
    ~_string() {
        _delete_data(_str);
        _str_len = 0;
        _str_cap = 0;
        _increaseBy = container_increase_step::value;
    }

public:
    friend bool operator==(const _string& lhs, const _string& rhs) { return lhs._compare(rhs) == 0; }
    friend bool operator!=(const _string& lhs, const _string& rhs) { return lhs._compare(rhs) != 0; }
    friend bool operator<(const _string& lhs, const _string& rhs) { return lhs._compare(rhs) < 0; }
    friend bool operator>(const _string& lhs, const _string& rhs) { return lhs._compare(rhs) > 0; }
    friend bool operator<=(const _string& lhs, const _string& rhs) { return lhs._compare(rhs) <= 0; }
    friend bool operator>=(const _string& lhs, const _string& rhs) { return lhs._compare(rhs) >= 0; }

private:
    int32_t _compare(const _string& rhs) const {
        if (!_str && !rhs._str)
            return 0;
        if (_str && !rhs._str)
            return 1;
        if (!_str && rhs._str)
            return -1;
        if (_str_len < rhs._str_len)
            return 1;
        if (_str_len > rhs._str_len)
            return -1;
        return strcmp(_str, rhs._str);
    }

public:
    const char& operator[](std::size_t i) const { return *(_str + i); }
    char& operator[](std::size_t i) { return *(_str + i); }
    const char& at(std::size_t i) const {
        if (i < 0 || _str_len <= i)
            throw;
        return operator[](i);
    }
    char& at(std::size_t i) {
        if (i < 0 || _str_len <= i)
            throw;
        return operator[](i);
    }
    const char& front() const { return operator[](0); }
    char& front() { return operator[](0); }
    const char& back() const { return operator[](_str_len - 1); }
    char& back() { return operator[](_str_len - 1); }
    // Iterators
public:
    iterator begin() { return _ibegin(); }
    const_iterator begin() const { return _ibegin(); }
    iterator end() { return _end(); }
    const_iterator end() const { return _end(); }
    const_iterator cbegin() const { return _ibegin(); }
    const_iterator cend() const { return _end(); }

    reverse_iterator rbegin() { return _rbegin(); }
    const_reverse_iterator rbegin() const { return _rbegin(); }
    reverse_iterator rend() { return _end(); }
    const_reverse_iterator rend() const { return _end(); }
    const_reverse_iterator crbegin() const { return _rbegin(); }
    const_reverse_iterator crend() const { return _end(); }

private:
    inline string_iterator_type _ibegin() const { return string_iterator_type(_str, &_str_len, 0); }
    inline string_iterator_type _rbegin() const { return string_iterator_type(_str, &_str_len, _str_len - 1); }
    inline string_iterator_type _end() const { return string_iterator_type(_str, &_str_len, _str_len); }
    std::size_t _getLength(const const_iterator first, const const_iterator second) {
        if (first.current().first_ != second.current().first_) {
            throw;
        }
        if (first.current().pos_ > second.current().pos_) {
            throw;
        }
        return second.current().pos_ - first.current().pos_;
    }

    //	Modifiers
public:
    _string& operator+=(const _string& s) {
        _append(s._str, s._str_len);
        return *this;
    }
    _string& operator+=(const char* s) {
        _append(s);
        return *this;
    }
    _string& operator+=(char c) {
        _append(&c, 1);
        return *this;
    }
    _string operator+(const _string& s) const {
        _string ret(*this);
        ret += s;
        return ret;
    }
    _string operator+(const char* s) const {
        _string ret(*this);
        ret += s;
        return ret;
    }
    _string operator+(char c) const {
        _string ret(*this);
        ret += c;
        return ret;
    }

    _string& append(const _string& other) {
        _append(other._str, other._str_len);
        return *this;
    }
    _string& append(const _string& other, std::size_t subpos, std::size_t sublen = container_npos::value) {
        sublen = _getLength(other, subpos, sublen);
        char* buffer = nullptr;
        _substr(buffer, other._str, subpos, sublen);
        if (buffer == nullptr)
            return *this;
        _append(buffer, sublen);
        _delete_data(buffer);
        return *this;
    }
    _string& append(const char* other) {
        _append(other);
        return *this;
    }
    _string& append(const char* s, std::size_t n) {
        if (s == nullptr || strlen(s) == 0)
            return *this;
        if (strlen(s) < n)
            n = strlen(s);
        char* buffer = nullptr;
        _substr(buffer, s, 0, n);
        if (buffer == nullptr)
            return *this;
        _append(buffer, n);
        _delete_data(buffer);
        return *this;
    }
    _string& append(std::size_t n, char c) {
        char* buffer = nullptr;
        _alloc_cstring(buffer, n, c);
        if (buffer == nullptr)
            return *this;
        _append(buffer, n);
        _delete_data(buffer);
        return *this;
    }
    _string& append(const const_iterator first, const const_iterator second) {
        const std::size_t n = _getLength(first, second);
        if (n != 0) {  // if length is not zero then _append
            char* buffer = nullptr;
            _alloc_cstring(buffer, n, first, second);
            if (buffer == nullptr)
                return *this;
            _append(buffer, n);
            _delete_data(buffer);
        }
        return *this;
    }

    _string& push_back(char c) {
        _append(&c, 1);
        return *this;
    }

    _string& insert(std::size_t pos, const _string& other) {
        _insert_str(pos, other._str, other._str_len);
        return *this;
    }
    _string& insert(std::size_t pos, const _string& other, std::size_t subpos, std::size_t sublen = container_npos::value) {
        sublen = _getLength(other, subpos, sublen);
        char* buffer = nullptr;
        _substr(buffer, other._str, subpos, sublen);
        _insert_str(pos, buffer, sublen);
        _delete_data(buffer);
        return *this;
    }
    _string& insert(std::size_t pos, const char* other) {
        _insert_str(pos, other);
        return *this;
    }
    _string& insert(std::size_t pos, const char* s, std::size_t n) {
        char* buffer = nullptr;
        _substr(buffer, s, 0, n);
        _insert_str(pos, buffer, n);
        _delete_data(buffer);
        return *this;
    }
    _string& insert(std::size_t pos, std::size_t n, char c) {
        char* buffer = nullptr;
        _alloc_cstring(buffer, n, c);
        _insert_str(pos, buffer, n);
        _delete_data(buffer);
        return *this;
    }
    void insert(iterator p, std::size_t n, char c) {
        char* buffer = nullptr;
        _alloc_cstring(buffer, n, c);
        _insert_str(p.current().pos_, buffer, n);
        _delete_data(buffer);
    }
    iterator insert(iterator p, char c) {
        _insert_str(p.current().pos_, &c, 1);
        return p;
    }
    void insert(iterator p, const const_iterator begin, const const_iterator last) {
        const std::size_t n = _getLength(begin, last);
        if (n == 0)
            return;
        char* buffer = nullptr;
        _alloc_cstring(buffer, n, begin, last);
        _insert_str(p.current().pos_, buffer, n);
        _delete_data(buffer);
    }

    _string& erase(std::size_t pos = 0, std::size_t len = container_npos::value) {
        _erase(pos, len);
        return *this;
    }
    iterator erase(const_iterator p) {
        _erase(p.current().pos_, 1);
        return p.current();
    }
    iterator erase(const_iterator first, const_iterator last) {
        _erase(first.current().pos_, _getLength(first, last));
        return first.current();
    }

    _string& replace(std::size_t pos, std::size_t len, const _string& other) {
        _replace(pos, len, other._str, other._str_len);
        return *this;
    }
    _string& replace(const_iterator i1, const_iterator i2, const _string& other) {
        replace(i1.current().pos_, _getLength(i1, i2), other._str, other._str_len);
        return *this;
    }
    _string& replace(std::size_t pos, std::size_t len, const _string& other, std::size_t subpos, std::size_t sublen = container_npos::value) {
        sublen = _getLength(other, subpos, sublen);
        char* buffer = nullptr;
        _substr(buffer, other._str, subpos, sublen);
        _replace(pos, len, buffer, strlen(buffer));
        _delete_data(buffer);
        return *this;
    }
    _string& replace(std::size_t pos, std::size_t len, const char* s) {
        _replace(pos, len, s, strlen(s));
        return *this;
    }
    _string& replace(const_iterator i1, const_iterator i2, const char* other) {
        _replace(i1.current().pos_, _getLength(i1, i2), other, strlen(other));
        return *this;
    }
    _string& replace(std::size_t pos, std::size_t len, const char* other, std::size_t n) {
        _replace(pos, len, other, n);
        return *this;
    }
    _string& replace(const_iterator i1, const_iterator i2, const char* other, std::size_t n) {
        _replace(i1.current().pos_, _getLength(i1, i2), other, n);
        return *this;
    }
    _string& replace(std::size_t pos, std::size_t len, std::size_t n, char c) {
        char* buffer = nullptr;
        _alloc_cstring(buffer, n, c);
        _replace(pos, len, buffer, n);
        _delete_data(buffer);
        return *this;
    }
    _string& replace(const_iterator i1, const_iterator i2, std::size_t n, char c) {
        char* buffer = nullptr;
        _alloc_cstring(buffer, n, c);
        _replace(i1.current().pos_, _getLength(i1, i2), buffer, n);
        _delete_data(buffer);
        return *this;
    }
    _string& replace(const_iterator i1, const_iterator i2, const_iterator first, const_iterator second) {
        const std::size_t n = _getLength(first, second);
        char* buffer = nullptr;
        _alloc_cstring(buffer, n, first, second);
        _replace(i1.current().pos_, _getLength(i1, i2), buffer, n);
        _delete_data(buffer);
        return *this;
    }

    void swap(_string& other) {
        _string temp = std::move(*this);
        *this = std::move(other);
        other = std::move(temp);
    }
    _string& pop_back() {
        _erase((end() - 1).current().pos_, 1);
        return *this;
    }

private:
    inline void _append(const char* other) {
        if (other == nullptr)
            return;
        _append(other, strlen(other));
    }
    void _append(const char* other, std::size_t n) {
        if (!other || n == 0)
            return;
        _increaseCapacity(_str_len + n);
        std::size_t i = 0;
        for (; i < n; ++i)
            operator[](_str_len + i) = other[i];
        operator[](_str_len + i) = '\0';
        _setLength(_str_len + n);
    }
    void _insert_str(std::size_t pos, const char* other) {
        if (other != nullptr)
            _insert_str(pos, other, strlen(other));
    }
    void _insert_str(std::size_t pos, const char* other, std::size_t n) {
        if (pos == _str_len) {
            return _append(other, n);
        }
        if (pos > _str_len) {
            throw;
        }
        if (n == 0) {
            return;
        }
        _increaseCapacity(_str_len + n);
        if (_str) {
            char* buffer = nullptr;
            _substr(buffer, _str, pos, _str_len);
            _clear_str(pos);
            _append(other, n);
            _append(buffer, strlen(buffer));
            _delete_data(buffer);
        } else {
            _append(other, n);
        }
    }
    void _substr(char*& buffer, const char* other, std::size_t pos = 0, std::size_t len = container_npos::value) const {
        if (other == nullptr) {
            return;
        }
        _alloc_cstring(buffer, len);
        for (std::size_t i = 0; i < len; ++i) {
            buffer[i] = other[pos + i];
        }
    }
    void _erase(std::size_t pos, std::size_t len) {
        len = _getLength(*this, pos, len);
        for (std::size_t i = pos + len; i < _str_len; ++i)
            operator[](i - len) = operator[](i);
        _clear_str(_str_len - len);
    }
    void _replace(std::size_t pos, std::size_t len, const char* other, std::size_t n) {
        len = _getLength(*this, pos, len);
        char* buffer = nullptr;
        _substr(buffer, _str, pos + len, _str_len);
        _clear_str(pos);
        char* replace_buffer = nullptr;
        _substr(replace_buffer, other, 0, n);
        _append(replace_buffer);
        _append(buffer);
        _delete_data(replace_buffer);
        _delete_data(buffer);
    }
    std::size_t _getLength(const _string& str, std::size_t pos, std::size_t len = container_npos::value) const {
        if (len == container_npos::value)
            len = _str_len - pos;

        if (pos + len > str._str_len) {
            return 0;
        }
        return len;
    }

public:
    const char* c_str() const { return (_str_len > 0 && _str) ? _str : ""; }

    std::size_t copy(char* s, std::size_t len, std::size_t pos = 0) const {
        if (!s)
            throw;
        len = _getLength(*this, pos, len);
        for (std::size_t i = 0; i < len; ++i)
            *(s + i) = operator[](pos + i);
        return len;
    }

    std::size_t find(const _string& other, std::size_t pos = 0) const { return _find(other._str, other._str_len, pos); }
    std::size_t find(const char* s, std::size_t pos = 0) const { return _find(s, strlen(s), pos); }
    std::size_t find(const char* s, std::size_t pos, std::size_t n) const { return _find(s, n, pos); }
    std::size_t find(char c, std::size_t pos = 0) const { return _find(&c, 1, pos); }

    std::size_t rfind(const _string& other, std::size_t pos = container_npos::value) const { return _rfind(other._str, other._str_len, pos); }
    std::size_t rfind(const char* s, std::size_t pos = container_npos::value) const { return _rfind(s, strlen(s), pos); }
    std::size_t rfind(const char* s, std::size_t pos, std::size_t n) const { return _rfind(s, n, pos); }
    std::size_t rfind(char c, std::size_t pos = container_npos::value) const { return _rfind(&c, 1, pos); }

    std::size_t find_first_of(const _string& other, std::size_t pos = 0) const { return _find_first_of(other._str, other._str_len, pos, true); }
    std::size_t find_first_of(const char* other, std::size_t pos = 0) const { return _find_first_of(other, strlen(other), pos, true); }
    std::size_t find_first_of(const char* other, std::size_t pos, std::size_t n) const { return _find_first_of(other, n, pos, true); }
    std::size_t find_first_of(char c, std::size_t pos = 0) const { return _find_first_of(&c, 1, pos, true); }

    std::size_t find_last_of(const _string& other, std::size_t pos = nstd::container_npos::value) const {
        return _find_last_of(other._str, other._str_len, pos, true);
    }
    std::size_t find_last_of(const char* other, std::size_t pos = nstd::container_npos::value) const {
        return _find_last_of(other, strlen(other), pos, true);
    }
    std::size_t find_last_of(const char* other, std::size_t pos, std::size_t n) const { return _find_last_of(other, n, pos, true); }
    std::size_t find_last_of(char c, std::size_t pos = nstd::container_npos::value) const { return _find_last_of(&c, 1, pos, true); }

    std::size_t find_first_not_of(const _string& other, std::size_t pos = 0) const { return _find_first_of(other._str, other._str_len, pos, false); }
    std::size_t find_first_not_of(const char* other, std::size_t pos = 0) const { return _find_first_of(other, strlen(other), pos, false); }
    std::size_t find_first_not_of(const char* other, std::size_t pos, std::size_t n) const { return _find_first_of(other, n, pos, false); }
    std::size_t find_first_not_of(char c, std::size_t pos = 0) const { return _find_first_of(&c, 1, pos, false); }

    std::size_t find_last_not_of(const _string& other, std::size_t pos = nstd::container_npos::value) const {
        return _find_last_of(other._str, other._str_len, pos, false);
    }
    std::size_t find_last_not_of(const char* other, std::size_t pos = nstd::container_npos::value) const {
        return _find_last_of(other, strlen(other), pos, false);
    }
    std::size_t find_last_not_of(const char* other, std::size_t pos, std::size_t n) const { return _find_last_of(other, n, pos, false); }
    std::size_t find_last_not_of(char c, std::size_t pos = nstd::container_npos::value) const { return _find_last_of(&c, 1, pos, false); }

    _string substr(std::size_t pos = 0, std::size_t len = container_npos::value) const {
        len = _getLength(*this, pos, len);
        char* buffer = nullptr;
        _substr(buffer, _str, pos, len);
        _string toReturn(buffer);
        _delete_data(buffer);
        return toReturn;
    }

private:
    std::size_t _find(const char* other, std::size_t len, std::size_t pos) const {
        std::size_t toReturn = container_npos::value;
        if (pos == container_npos::value)
            pos = _str_len - 1;
        for (; pos <= _str_len - len; ++pos)
            if (operator[](pos) == *other && _find_compare(other, len, pos)) {
                toReturn = pos;
                break;
            }
        return toReturn;
    }
    std::size_t _rfind(const char* other, std::size_t len, std::size_t pos) const {
        std::size_t toReturn = container_npos::value;
        if (pos == container_npos::value || pos + len > _str_len + 1)
            pos = _str_len - len + 1;

        for (std::size_t i = pos; 0 <= i; --i)
            if (operator[](i) == *other && _find_compare(other, len, i)) {
                toReturn = i;
                break;
            }
        return toReturn;
    }
    bool _find_compare(const char* other, std::size_t len, std::size_t pos) const {
        for (std::size_t i = 1; i < len; ++i)
            if (operator[](pos + i) != *(other + i))
                return false;
        return true;
    }
    std::size_t _find_first_of(const char* other, std::size_t len, std::size_t pos, bool isTrue) const {
        std::size_t toReturn = container_npos::value;
        if (pos == container_npos::value)
            pos = _str_len - 1;

        for (; pos < _str_len; ++pos)
            if (_find_of_compare(other, len, pos, isTrue)) {
                toReturn = pos;
                break;
            }
        return toReturn;
    }
    std::size_t _find_last_of(const char* other, std::size_t len, std::size_t pos, bool isTrue) const {
        std::size_t toReturn = container_npos::value;
        if (pos == container_npos::value)
            pos = _str_len - 1;

        for (std::size_t i = pos; 0 <= i; --i)
            if (_find_of_compare(other, len, i, isTrue)) {
                toReturn = i;
                break;
            }
        return toReturn;
    }
    bool _find_of_compare(const char* other, std::size_t len, std::size_t pos, bool isTrue) const {
        for (std::size_t i = 0; i < len; ++i)
            if (operator[](pos) == *(other + i))
                return isTrue;
        return !isTrue;
    }

public:
    std::size_t length() const { return _str_len; }
    inline std::size_t size() const { return length(); }
    std::size_t max_size() const { return nstd::container_npos::value - 1; }
    void resize(std::size_t n) {
        if (_str_len == n)
            return;
        if (_str_len < n) {
            _setLength(n);
            return;
        }
        _clear_str(n);
    }
    void resize(std::size_t n, char c) {
        if (_str_len == n)
            return;
        if (_str_len < n) {
            std::size_t pos = _str_len;
            _setLength(n);
            _fill_str(_str, _str_len, pos, c);
            return;
        }
        _clear_str(n);
    }
    std::size_t capacity() const { return _str_cap; }
    void reserve(std::size_t n = 0) {
        if (_str_cap == n)
            return;
        if (_str_cap < n) {
            _setCapacity(n);
            return;
        }
        if (_str_cap / 2 > _str_len) {
            _decreaseCapacity(_str_cap / 2);
        }
    }
    void clear() { _clear_str(0); }
    bool empty() const { return _str_len ? false : true; }
    void shrink_to_fit() { _decreaseCapacity(_str_len); }

private:
    void _setLength(const std::size_t len) {
        if (_str_len > len)
            _clear_str(len);
        else if (_str_cap < len)
            _increaseCapacity(len);
        _str_len = len;
    }
    void _setCapacity(const std::size_t cap) {
        if (_str_cap == cap && _str)
            return;
        if (cap < _str_len)
            return;
        _str_cap = cap;

        char* buffer = _str;
        _str = nullptr;
        _alloc_cstring(_str, _str_cap);
        if (buffer) {
            for (std::size_t i = 0; i < _str_len; ++i)
                operator[](i) = buffer[i];
            operator[](_str_len) = '\0';
            _delete_data(buffer);
        }
    }
    void _increaseCapacity(const std::size_t cap) {
        if (_str_cap > cap && _str)
            return;
        std::size_t _cap = _str_cap;
        while (_cap <= cap)
            _cap += _increaseBy;
        _increaseBy++;
        _setCapacity(_cap);
    }
    void _decreaseCapacity(const std::size_t cap) {
        if (_str_cap < cap)
            return;
        if (_increaseBy > container_increase_step::value)
            --_increaseBy;
        _setCapacity(cap);
    }
    void _alloc_cstring(char*& buffer, const std::size_t n) const {
        if (buffer)
            throw;
        buffer = _new_data(n + 1);
    }
    void _alloc_cstring(char*& buffer, const std::size_t n, char c) const {
        _alloc_cstring(buffer, n);
        _fill_str(buffer, n, 0, c);
    }
    void _alloc_cstring(char*& buffer, const std::size_t n, const const_iterator i1, const const_iterator i2) const {
        _alloc_cstring(buffer, n);
        const_iterator begin = i1;
        for (std::size_t i = 0; i < n; ++i)
            buffer[i] = *begin++;
    }
    void _fill_str(char* other, const std::size_t len, std::size_t pos, char c) const {
        if (other == nullptr)
            return;
        std::size_t begin = pos;
        while (begin != len)
            other[begin++] = c;
        other[begin] = '\0';
    }
    void _clear_str(const std::size_t pos) {
        _fill_str(_str, _str_len, pos, '\0');
        _str_len = pos;
    }
    char* _new_data(std::size_t count) const {
        if (malloc_fun_ != nullptr)
            return malloc_fun_(count);
        else
            return memory::safe_malloc_container_element<char>(count);
    }
    void _delete_data(char*& data) const {
        if (data == nullptr)
            return;
        if (delete_fun_ != nullptr) {
            delete_fun_(data);
        } else {
            memory::safe_delete_container_element<char>(data);
        }
    }

private:
    char* _str;
    std::size_t _str_len;
    std::size_t _str_cap;
    std::size_t _increaseBy = container_increase_step::value;
    element_malloc_fun_t<char> malloc_fun_;
    element_delete_fun_t<char> delete_fun_;
};
using string = _string<>;
namespace {
struct _ABS {
    static uint32_t abs(uint32_t value) { return value; };
    static uint64_t abs(uint64_t value) { return value; };
    static int32_t abs(int32_t value) { return ::abs(value); };
    static int64_t abs(int64_t value) {
#ifdef NE_STL_OS_WIN
        return ::_abs64(value);
#else
        return (int64_t)::fabs(value);
#endif  // NE_STL_OS_WIN
    };
};
template <typename T>
typename std::enable_if<std::numeric_limits<T>::is_signed, bool>::type is_valuenegative(T value) {
    static_assert(std::numeric_limits<T>::is_specialized, "Argument must be numeric.");
    return value < 0;
}
template <typename T>
typename std::enable_if<!std::numeric_limits<T>::is_signed, bool>::type is_valuenegative(T) {
    static_assert(std::numeric_limits<T>::is_specialized, "Argument must be numeric.");
    return false;
}
template <typename TInt>
nstd::string int2string(TInt value) {
    const size_t kOutputBufSize = 3 * sizeof(TInt) + std::numeric_limits<TInt>::is_signed;
    using chr_t = typename nstd::string::value_type;
    chr_t outbuf[kOutputBufSize];
    auto res = _ABS::abs(value);
    chr_t* end = outbuf + kOutputBufSize;
    chr_t* i = end;
    do {
        --i;
        *i = static_cast<chr_t>((res % 10) + '0');
        res /= 10;
    } while (res != 0);
    if (is_valuenegative(value)) {
        --i;
        *i = static_cast<chr_t>('-');
    }
    return nstd::string(i, end - i);
}
}  // namespace
}  // namespace nstd

template <>
struct std::hash<nstd::string> {
    std::size_t operator()(const nstd::string& ne_str) const noexcept { return std::hash<std::string>{}(ne_str.c_str()); }
};

#endif  // !NE_STL_INCLUDENE_STL_STRING_
